package solver

func valuesForHidden(valueCounts [9]int, hiddenCount int) []int {
	values := []int{}
	for value, valueCount := range valueCounts {
		if valueCount == 0 || valueCount > hiddenCount {
			continue
		}
		values = append(values, value)
	}
	return values
}

func verifyHidden(values []int, valueCells [9][9]bool) (hidden bool, cellNums []int) {
	cells := [9]bool{}
	for _, value := range values {
		for i, cell := range valueCells[value] {
			cells[i] = cells[i] || cell
		}
	}

	cellCount := 0
	for _, cell := range cells {
		if cell {
			cellCount++
		}
	}
	hidden = cellCount == len(values)

	if !hidden {
		return
	}
	for i, Cell := range cells {
		if Cell {
			cellNums = append(cellNums, i)
		}
	}
	return
}

func clearupHiddenHouse(house *House, values []int, cellNums []int) (used bool) {
	for _, cellNum := range cellNums {
		cell := house.cells[cellNum]
		if cell.removeCandidateBut(values) {
			used = true
		}
	}
	return
}

func hiddenHouse(house *House, hiddenCount int) (used bool) {
	valueCells, valueCounts := sumupCandCells(house)
	values := valuesForHidden(valueCounts, hiddenCount)
	subsets := combine(values, hiddenCount)
	for _, subset := range subsets {
		hidden, cellNums := verifyHidden(subset, valueCells)
		if !hidden {
			continue
		}
		if clearupHiddenHouse(house, subset, cellNums) {
			used = true
		}
	}

	return
}

func (g *Grid) HiddenPairHouse(house *House) (used bool) {
	return hiddenHouse(house, 2)
}

func (g *Grid) HiddenPair() (used bool) {
	return g.doStrategy(g.HiddenPairHouse)
}

func (g *Grid) HiddenTripleHouse(house *House) (used bool) {
	return hiddenHouse(house, 3)
}

func (g *Grid) HiddenTriple() (used bool) {
	return g.doStrategy(g.HiddenTripleHouse)
}

func (g *Grid) HiddenQuandrupleHouse(house *House) (used bool) {
	return hiddenHouse(house, 4)
}

func (g *Grid) HiddenQuandruple() (used bool) {
	return g.doStrategy(g.HiddenQuandrupleHouse)
}
